import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.behaviors.vp.*;
import javax.swing.JFrame;
import java.util.*;
import simpleParticleSystemPackage.*;

/**
* Beispiel fuer ein Partikelsystem in Form einer Wunderkerze
*
* @author Frank Klawonn
* Letzte Aenderung 1.8.2008
*/
public class ParticleSystemExample extends JFrame
{

  //Der Canvas, auf den gezeichnet wird.
  public Canvas3D myCanvas3D;


  public ParticleSystemExample()
  {
    //Mechanismus zum Schliessen des Fensters und beenden des Programms
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    //Standardeinstellung fuer das Betrachteruniversum
    myCanvas3D = new Canvas3D(SimpleUniverse.getPreferredConfiguration());


    //Aufbau des SimpleUniverse:
    //Zuerst Erzeugen zusammen mit dem Canvas
    SimpleUniverse simpUniv = new SimpleUniverse(myCanvas3D);


    //Standardpositionierung des Betrachters
    simpUniv.getViewingPlatform().setNominalViewingTransform();


    //Die Szene wird in dieser Methode erzeugt.
    createSceneGraph(simpUniv);


    //Hinzufuegen von Licht
    addLight(simpUniv);


    //Hierdurch kann man mit der Maus den Betrachterstandpunkt veraendern
    OrbitBehavior ob = new OrbitBehavior(myCanvas3D);
    ob.setSchedulingBounds(new BoundingSphere(new Point3d(0.0,0.0,0.0),Double.MAX_VALUE));
    simpUniv.getViewingPlatform().setViewPlatformBehavior(ob);


    //Darstellung des Canvas/Fensters:
    setTitle("A simple particle system");
    setSize(700,700);
    getContentPane().add("Center", myCanvas3D);
    setVisible(true);

  }




  public static void main(String[] args)
  {

     ParticleSystemExample sa = new ParticleSystemExample();
  }


  //In dieser Methode werden die Objekte der Szene aufgebaut, die Bewegungen
  //definiert und dem SimpleUniverse su hinzugefuegt.
  public void createSceneGraph(SimpleUniverse su)
  {

 
      //Laenge der Wunderkerze (Funken spruehender Bereich)
      float rodLength = 0.2f;

      //Laenge des Griffs
      float handleLength = 0.6f * rodLength;
      
      //Radius des Funken spruehenden Bereichs
      float rodRadius = 0.02f;

      //Radius des Griffs
      float handleRadius = 0.5f*rodRadius;


      //Appearance fuer den Funken spruehenden Bereich
      Appearance darkApp = new Appearance();
      setToMyDefaultAppearance(darkApp,new Color3f(0.1f,0.1f,0.1f));


      //Zylinder fuer den Funken spruehenden Bereich
      Cylinder rod = new Cylinder(rodRadius, rodLength,darkApp);


      //Appearance fuer den Griff
      Appearance lightApp = new Appearance();
      setToMyDefaultAppearance(lightApp,new Color3f(0.8f,0.8f,0.8f));
 
      //Zylinder fuer den Griff
      Cylinder handle = new Cylinder(handleRadius, handleLength,lightApp);

      //Positionierung des Griffs
      Transform3D tfHandle = new Transform3D();
      tfHandle.setTranslation(new Vector3f(0.0f,-(rodLength+handleLength)/2,0.0f));
      TransformGroup tgHandle = new TransformGroup(tfHandle);
      tgHandle.addChild(handle);







      //Hier wird die Transformationsgruppe fuer das Partikelsystem erzeugt
      TransformGroup tgParticleSystem = new TransformGroup();
      tgParticleSystem.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
      tgParticleSystem.setCapability(TransformGroup.ALLOW_CHILDREN_EXTEND);

      Transform3D tfSparkler = new Transform3D();
      tfSparkler.setTranslation(new Vector3f(0.2f,handleLength+rodLength/2,0.0f));
      TransformGroup tgSparkler = new TransformGroup(tfSparkler);

      tgSparkler.addChild(rod);
      tgSparkler.addChild(tgHandle);
      tgSparkler.addChild(tgParticleSystem);



      TransformGroup tgmSparkler = new TransformGroup();

      tgmSparkler.addChild(tgSparkler);

      Transform3D rotationAxis = new Transform3D();



      //Die Wunderkerze soll eine kreisfoermige Bewegung ausfuehren.
      Alpha boxAlpha = new Alpha(-1,4000);



      RotationInterpolator sparklerRotation = new RotationInterpolator(boxAlpha,tgmSparkler,
                                               rotationAxis,0.0f,(float) Math.PI*2);

      BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0),Double.MAX_VALUE);
      sparklerRotation.setSchedulingBounds(bounds);

      //Die Bewegung wird zur Transformationsgruppe hinzugefuegt.
      tgmSparkler.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
      tgmSparkler.addChild(sparklerRotation);











//*** Die Wurzel des Graphen, der die Szene enthaelt. ***
    BranchGroup theScene = new BranchGroup();


    //Fuege die Wunderkerze zur Szene
    theScene.addChild(tgmSparkler);


    //Hier wird das Partikelsystem erzeugt
    SimpleParticleSystem sps = new SimpleParticleSystem(tgParticleSystem);
    //sps.startPosition = new RandomRectangleVector3fCreator(0,rodLength/2);
    sps.direction = new RandomDirectionCreator2(Math.PI,0.2);
    sps.lifeSpan = new RandomLongCreator(200,400);
    sps.interarrivalTime = new ConstantLongCreator(25);
    Appearance app = new Appearance();
    Color3f col = new Color3f(0.9f,0.9f,0.0f);
    setToMyDefaultAppearance(app,col);


    //sps.particleCreator = new ConstantTetrahedronCreator(0.002f,app);
    sps.particleCreator = new LineOfSparksCreator(0.005f,app,10,rodLength,0.1f);
    sps.activateParticleSystem();




  


    theScene.compile();

    //Hinzufuegen der Szene
    su.addBranchGraph(theScene);








  }


  /**
  * Erzeugt eine Standardoberflaechenstruktur in einer gewuenschten Farbe
  *
  * @param app      Die Appearance, mit der die Oberflaeche belegt werden soll
  * @param col      Die gewuenschte Farbe
  */
  public static void setToMyDefaultAppearance(Appearance app, Color3f col)
  {
    app.setMaterial(new Material(col,col,col,col,150.0f));
  }



  //Hier wird etwas Licht zu der Szene hinzugefuegt.
  public void addLight(SimpleUniverse su)
  {

    BranchGroup bgLight = new BranchGroup();

    BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);
    Color3f lightColour1 = new Color3f(1.0f,1.0f,1.0f);
    Vector3f lightDir1  = new Vector3f(-1.0f,0.0f,-0.5f);
    DirectionalLight light1 = new DirectionalLight(lightColour1, lightDir1);
    light1.setInfluencingBounds(bounds);

    bgLight.addChild(light1);
    su.addBranchGraph(bgLight);
  }




}
